#pragma warning disable VerifySetParameters
namespace VerifyMSTest;

public static partial class Verifier
{
    static Task AddFile(string path)
    {
        var context = CurrentTestContext.Value?.TestContext;
        context?.AddResultFile(path);
        return Task.CompletedTask;
    }

    [ModuleInitializer]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public static void AddAttachmentEvents() =>
        VerifierSettings.AddTestAttachment(AddFile);

    public static readonly AsyncLocal<TestExecutionContext?> CurrentTestContext = new();

    public static InnerVerifier BuildVerifier(VerifySettings settings, string sourceFile, bool useUniqueDirectory = false)
    {
        if (useUniqueDirectory)
        {
            settings.UseUniqueDirectory();
        }

        var context = GetTestContext();

        var assembly = context.Assembly;
        var type = context.TestClass;
        var method = context.Method;

        if (!settings.HasParameters)
        {
            var data = context.TestContext.TestData;
            if (data != null)
            {
                settings.SetParameters(data);
            }
        }

        VerifierSettings.AssignTargetAssembly(assembly);
        var pathInfo = GetPathInfo(sourceFile, type, method);
        return new(
            sourceFile,
            settings,
            type.NameWithParent(),
            method.Name,
            method.ParameterNames(),
            pathInfo);
    }

    internal static TestExecutionContext GetTestContext()
    {
        var context = CurrentTestContext.Value;
        if (context is null)
        {
            throw new("TestContext is null. Ensure test class has a `[UsesVerify]` attribute (or inherits from `VerifyBase`).");
        }

        return context;
    }

    [Pure]
    public static SettingsTask Verify(
        object? target,
        IEnumerable<Target> rawTargets,
        VerifySettings? settings = null,
        [CallerFilePath] string sourceFile = "") =>
        Verify(settings, sourceFile, _ => _.Verify(target, rawTargets));

    [Pure]
    public static SettingsTask Verify(
        IEnumerable<Target> targets,
        VerifySettings? settings = null,
        [CallerFilePath] string sourceFile = "") =>
        Verify(settings, sourceFile, _ => _.Verify(targets));

    [Pure]
    public static SettingsTask Verify(
        Target target,
        VerifySettings? settings = null,
        [CallerFilePath] string sourceFile = "") =>
        Verify(settings, sourceFile, _ => _.Verify(target));

    static SettingsTask Verify(
        VerifySettings? settings,
        string sourceFile,
        Func<InnerVerifier, Task<VerifyResult>> verify,
        bool useUniqueDirectory = false)
    {
        Guards.AgainstBadSourceFile(sourceFile);
        return new(
            settings,
            async settings =>
            {
                using var verifier = BuildVerifier(settings, sourceFile, useUniqueDirectory);
                return await verify(verifier);
            });
    }
}